package table;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import nodes.Type;
import visitors.SymbolTablePrettyPrintVisitor;

public final class FunctionDeclaration extends Declaration {
    
    private final List<Type> params;
    private final Type returnType;
    private volatile int hashCode;

    public FunctionDeclaration(List<Type> params, Type returnType)
    {
        if (params==null || returnType == null)
        {
            throw new NullPointerException("Constructor parameters cannot be null!");
        }
        ArrayList<Type> temp = new ArrayList<Type>(params);
        this.params = Collections.unmodifiableList(temp);
        this.returnType = returnType;
    }

    public List<Type> getParams()
    {
        return params;
    }

    public Type getReturnType()
    {
        return returnType;
    }

    /**
     * Checks if params list is equal to the list of
     * parameters of this FunctionDeclaration.
     *
     * Params list is equal to the list of
     * parameters of this FunctionDeclaration,
     * if both lists are of the same size
     * and for every element in both lists, their types are equal,
     * or the params element is UNDEF.
     *
     *
     * @param params List of parameters to compare
     *        against this FunctionDeclaration
     * @return
     */
    public boolean hasParameters(List<Type> params)
    {
        if (this.params.size() != params.size())
            return false;
        for (int i = 0; i < this.params.size(); i++)
        {
            if (this.params.get(i)!=params.get(i) && !Type.isUndef(params.get(i)))
                return false;
        }
        return true;
    }

    /**
     * Compares o to this FunctionDeclaration.
     * Two FunctionDeclarations are equal
     * if they have the same amount of parameters
     * and for every parameter, they are either equal,
     * or o's parameter is UNDEF.
     * 
     *
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (o.getClass() != getClass())
            return false;
        FunctionDeclaration o1 = (FunctionDeclaration) o;
        if (params.size() != o1.params.size())
            return false;
        for (int i = 0; i < params.size(); i++)
        {
            if (params.get(i)!=o1.params.get(i) && !Type.isUndef(o1.params.get(i)))
                return false;
        }
        return true;
    }

    @Override
    public int hashCode()
    {
        int result = hashCode;
        if (result==0)
        {
            result = 17;
            result = 31 * result + params.hashCode();
            hashCode = result;
        }
        return result;
    }

    @Override
    public Object accept(SymbolTablePrettyPrintVisitor v)
    {
        return v.visit(this);
    }
}